use ::image;
use clap::Subcommand;
use image::{DynamicImage, GenericImageView, Rgba};
use imageproc::contours::{find_contours_with_threshold, Contour};
use imageproc::contrast::threshold;
use std::io;
use std::path::{Path, PathBuf};
use std::u32::MAX;

fn parse_rgba(s: &str) -> Result<Rgba<u8>, &'static str> {
  if s.is_empty() {
    return Ok(Rgba([255u8; 4]));
  }
  let parts = s.split(",");
  let ret: Vec<_> = parts.into_iter().flat_map(|v| v.parse::<u8>()).collect();
  if ret.len() != 4 {
    return Err("boudary_color格式:[255,255,255,255]");
  }
  return Ok(Rgba(ret.try_into().expect("use")));
}

#[derive(Debug, Subcommand)]
pub enum ImageComands {
  Binarization {
    file: PathBuf,
  },
  Recognition {
    file: PathBuf,
  },
  RecognitionEx {
    #[arg(short, long, value_parser = parse_rgba)]
    boudary_color: Rgba<u8>,

    #[arg(short, long, default_value_t = 1, default_missing_value = "1")]
    sampling_size: u32,

    #[arg(long, default_value_t = 0, default_missing_value = "0")]
    left_padding: u32,

    #[arg(long, default_value_t = 0, default_missing_value = "0")]
    right_padding: u32,

    #[arg(long, default_value_t = 0, default_missing_value = "0")]
    left_crop: u32,

    #[arg(long, default_value_t = 0, default_missing_value = "0")]
    right_crop: u32,

    #[arg(long, default_value_t = 0, default_missing_value = "0")]
    min_height: u32,

    #[arg(long, default_value_t = 999999)]
    max_height: u32,

    file: PathBuf,
  },
  Crop {
    file: PathBuf,
  },
}

pub fn serve(command: &ImageComands) {
  match command {
    ImageComands::Binarization { file } => {
      let path: &Path = file.as_ref();
      let new_file = Path::new(path).with_extension("");
      let new_file = Path::new(path).with_file_name(format!(
        "{}-grayb.png",
        new_file.file_name().unwrap().to_str().unwrap()
      ));
      if let Ok(()) = binarization_image(file, Some(&new_file)) {
        println!("done!");
      } else {
        eprintln!("can't binarization image!");
      }
    }
    ImageComands::Recognition { file } => {
      let img = image::open(file).unwrap();
      let image_luma = img.into_luma8();
      // let contours: Vec<Contour<_>> = find_contours::<_>(&image_luma);
      let contours: Vec<Contour<u32>> = find_contours_with_threshold(&image_luma, 130);
      for ct in contours {
        println!("contours=>\n {:?}", ct);
      }
    }
    ImageComands::RecognitionEx {
      boudary_color,
      sampling_size,
      left_padding,
      right_padding,
      left_crop,
      right_crop,
      min_height,
      max_height,
      file,
    } => {
      if let Ok((files, ..)) = ImageSegmentator::new(file)
        .set_boudary_color(*boudary_color)
        .set_sampling_size(*sampling_size)
        .set_left_padding(*left_padding)
        .set_right_padding(*right_padding)
        .set_left_crop(*left_crop)
        .set_right_crop(*right_crop)
        .set_min_height(*min_height)
        .set_max_height(*max_height)
        .split_save()
      {
        println!("done! => {:?}", files);
      } else {
        eprintln!("can't RecognitionEx image!");
      };
    }
    ImageComands::Crop { file } => {
      let img = image::open(file).unwrap();
      let cropped = img.crop_imm(355, 355, 700, 1820);
      cropped.save(file).expect("save cropped failed");
    }
  }
}

pub fn binarization_image<P>(src: P, dest: Option<P>) -> io::Result<()>
where
  P: AsRef<Path>,
{
  let path = src.as_ref();
  path.try_exists()?;
  let img = image::open(path).unwrap();
  let image_luma = img.into_luma8();
  threshold(&image_luma, 130);

  if let Ok(()) = image_luma.save(dest.unwrap_or(src)) {
    Ok(())
  } else {
    Err(io::Error::new(
      io::ErrorKind::Other,
      "save binarization fail",
    ))
  }
}

#[derive(Debug)]
pub struct Rect {
  x: u32,
  y: u32,
  w: u32,
  h: u32,
}

impl Rect {
  pub fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
    Rect { x, y, w, h }
  }
}

pub struct ImageBuilder<P>
where
  P: AsRef<Path>,
{
  path: P,
  crop: Option<Rect>,
  binarization: bool,
}

impl<P> ImageBuilder<P>
where
  P: AsRef<Path>,
{
  pub fn new(path: P) -> Self {
    ImageBuilder {
      path,
      crop: None,
      binarization: false,
    }
  }
  pub fn set_crop(&mut self, rect: Rect) -> &mut Self {
    self.crop = Some(rect);
    self
  }
  pub fn set_binarization(&mut self, binarization: bool) -> &mut Self {
    self.binarization = binarization;
    self
  }
  pub fn save(&self) -> io::Result<()> {
    let mut img = image::open(self.path.as_ref()).unwrap();
    if let Some(rect) = &self.crop {
      img = img.crop_imm(rect.x, rect.y, rect.w, rect.h);
    }

    let r = if self.binarization {
      let image_luma = img.into_luma8();
      threshold(&image_luma, 130);
      if let Ok(()) = image_luma.save(self.path.as_ref()) {
        Ok(())
      } else {
        Err(io::Error::new(
          io::ErrorKind::Other,
          "save binarization fail",
        ))
      }
    } else {
      if let Ok(()) = img.save(self.path.as_ref()) {
        Ok(())
      } else {
        Err(io::Error::new(io::ErrorKind::Other, "save img fail"))
      }
    };
    r
  }
}

pub struct ImageSegmentator<P>
where
  P: AsRef<Path>,
{
  path: P,
  boundary_color: Rgba<u8>,
  sampling_size: u32, //采样宽度
  left_padding: u32,  // 左填充
  right_padding: u32, // 右填充
  left_crop: u32,     // 切割的左缩紧
  right_crop: u32,    // 切割的右缩紧
  min_height: u32,    // 分割后的最小高度
  max_height: u32,    // 分割后的最大宽度
}

impl<P> ImageSegmentator<P>
where
  P: AsRef<Path>,
{
  pub fn new(path: P) -> Self {
    ImageSegmentator {
      path,
      boundary_color: Rgba([0, 0, 0, 0]),
      sampling_size: 1,
      left_padding: 0,
      right_padding: 0,
      left_crop: 0,
      right_crop: 0,
      min_height: 0,
      max_height: MAX,
    }
  }
  pub fn set_boudary_color(&mut self, boundary_color: Rgba<u8>) -> &mut Self {
    self.boundary_color = boundary_color;
    self
  }
  pub fn set_sampling_size(&mut self, sampling_size: u32) -> &mut Self {
    self.sampling_size = sampling_size;
    self
  }
  pub fn set_left_padding(&mut self, left_padding: u32) -> &mut Self {
    self.left_padding = left_padding;
    self
  }
  pub fn set_right_padding(&mut self, right_padding: u32) -> &mut Self {
    self.right_padding = right_padding;
    self
  }
  pub fn set_left_crop(&mut self, left_crop: u32) -> &mut Self {
    self.left_crop = left_crop;
    self
  }
  pub fn set_right_crop(&mut self, right_crop: u32) -> &mut Self {
    self.right_crop = right_crop;
    self
  }
  pub fn set_min_height(&mut self, min_height: u32) -> &mut Self {
    self.min_height = min_height;
    self
  }
  pub fn set_max_height(&mut self, max_height: u32) -> &mut Self {
    self.max_height = max_height;
    self
  }
  pub fn split(&self) -> io::Result<(Vec<(Rect, DynamicImage)>, u32, u32)> {
    let img = image::open(self.path.as_ref()).unwrap();
    let (w, _) = img.dimensions();
    println!("width:{:?}", w);
    let mut y_axises: Vec<u32> = vec![];
    let mut curr_y: u32 = 0;
    let mut last_line_is_boundary = false;
    let mut pixel_check_boundary = false;

    for pixel in img.pixels() {
      let is_begin_of_line = pixel.0 == 0;
      let is_end_of_line = pixel.0 == w - 1;

      // 行头检测
      if is_begin_of_line {
        curr_y = pixel.1;
        pixel_check_boundary = true;
      }

      // 如果检测到当前行已经不属于边界且不是行尾,设置并跳过
      if !pixel_check_boundary && !is_end_of_line {
        continue;
      }

      // 抽样指定的像素点检测边界
      if pixel.0 % self.sampling_size == (self.sampling_size - 1)
        && pixel.0 < w - self.right_padding
      {
        let rgba = pixel.2 .0;
        if Rgba(rgba) == self.boundary_color {
          // println!("pixel:{:?}", pixel);
          pixel_check_boundary = pixel_check_boundary && true;
        } else {
          pixel_check_boundary = false;
        }
      }

      // 行尾检测
      if is_end_of_line {
        // println!(
        //   "行尾检测{curr_y}=>last_line_is_boundary:{}",
        //   last_line_is_boundary
        // );
        // println!(
        //   "行尾检测{curr_y}=>pixel_check_boundary:{}",
        //   pixel_check_boundary
        // );
        if last_line_is_boundary {
          if !pixel_check_boundary {
            y_axises.push(curr_y - 1);
          }
        } else {
          if pixel_check_boundary {
            y_axises.push(curr_y);
          }
        }
        last_line_is_boundary = pixel_check_boundary;
      }
    }

    println!("split yAxises:{:?}", y_axises);

    //前提 因为分割线一定不止1px的高度,因此每条线占用2个y_axis
    assert_eq!(0, y_axises.len() % 2);
    let mut top_splitter = 0u32;
    let mut bottom_splitter = 0u32;
    let y_axises = match &y_axises[..] {
      [] => {
        println!("没有找到任何边界,不做处理!");
        return Ok((vec![], top_splitter, bottom_splitter));
      }
      [v] => {
        println!("只找到到一条边界(1px),不做处理!");
        return Ok((vec![], *v, *v));
      }
      [t, b] => {
        println!("只找到到一条边界(>1px),不做处理!");
        return Ok((vec![], *t, *b));
      }
      // 去除第一个和最后一个数据后,每两个元素组成top和bottom的边界
      [_, remains @ .., _] => remains
    };
    // // 去除第一个和最后一个数据后,每两个元素组成top和bottom的边界
    // let y_axises = &y_axises[1..y_axises.len() - 1];
    assert_eq!(0, y_axises.len() % 2);

    // top_splitter = y_axises[0];
    // bottom_splitter = y_axises[y_axises.len()-1];

    let (tops, bottoms): (Vec<(usize, &u32)>, Vec<(usize, &u32)>) = y_axises
      .into_iter()
      .enumerate()
      .partition(|(idx, _)| idx % 2 == 0);

    let (_, tops): (Vec<_>, Vec<u32>) = tops.into_iter().unzip();
    let (_, bottoms): (Vec<_>, Vec<u32>) = bottoms.into_iter().unzip();

    println!("tops:{:?}", tops);
    println!("bottoms:{:?}", bottoms);

    let splitted = tops.iter().zip(bottoms.iter()).filter_map(|p| {
      let rect_h = p.1 - p.0;
      if rect_h < self.min_height || rect_h > self.max_height {
        println!(
          "skip rect for => rect_h:{}, min_height:{}, max_height:{}",
          rect_h, self.min_height, self.max_height
        );
        return None;
      }
      let rect = Rect {
        x: self.left_crop,
        y: *p.0,
        w: w - self.left_crop - self.right_crop,
        h: rect_h,
      };
      // 取第一个截图的上边
      if top_splitter == 0 {
        top_splitter = rect.y;
      }
      // 取最大的下边
      if rect.y + rect_h > bottom_splitter {
        bottom_splitter = rect.y + rect_h;
      }
      let cropped = img.crop_imm(rect.x, rect.y, rect.w, rect.h);

      Some((rect, cropped))
    });

    Ok((splitted.collect(), top_splitter, bottom_splitter))
  }
  pub fn split_save(&self) -> io::Result<(Vec<String>, u32, u32)> {
    let (splitted, top_splitter, bottom_splitter) = self.split()?;
    let path = self.path.as_ref();
    let ext = path.extension().unwrap().to_str().unwrap();
    let filename = path.with_extension("").to_str().unwrap().to_string();

    let files = splitted.into_iter().flat_map(|(Rect { x, y, w, h }, img)| {
      println!("rect:Rect {{ x: {}, y: {}, w: {}, h: {} }}", x, y, w, h);
      let file = format!("{}_{}_{}_{}_{}.{}", filename, x, y, w, h, ext);
      if let Err(err) = img.save(file.as_str()) {
        eprintln!("save crop img err:{:?}", err);
        // return Err(io::Error::new(io::ErrorKind::Other, err));
        return None;
      }
      Some(file)
    });
    Ok((files.collect(), top_splitter, bottom_splitter))
  }
  // pub fn split_save2(&self) -> io::Result<Vec<String>> {
  //   let img = image::open(self.path.as_ref()).unwrap();
  //   let (w, _) = img.dimensions();
  //   println!("width:{:?}", w);
  //   let mut y_axises: Vec<u32> = vec![];
  //   let mut curr_y: u32 = 0;
  //   let mut last_line_is_boundary = false;
  //   let mut pixel_check_boundary = false;
  //   let mut is_begin_of_line = false;
  //   let mut is_end_of_line = false;

  //   for pixel in img.pixels() {
  //     is_begin_of_line = pixel.0 == 0;
  //     is_end_of_line = pixel.0 == w - 1;

  //     // 行头检测
  //     if is_begin_of_line {
  //       curr_y = pixel.1;
  //       pixel_check_boundary = true;
  //     }

  //     // 如果检测到当前行已经不属于边界且不是行尾,设置并跳过
  //     if !pixel_check_boundary && !is_end_of_line {
  //       continue;
  //     }

  //     // 抽样指定的像素点检测边界
  //     if pixel.0 % self.sampling_size == (self.sampling_size - 1)
  //       && pixel.0 < w - self.right_padding
  //     {
  //       let rgba = pixel.2 .0;
  //       // if rgba[0] == 245 && rgba[1] == 245 && rgba[2] == 245 {
  //       //   // yAxis.push(2);
  //       //   println!("pixel:{:?}", pixel);
  //       //   pixel_check_boundary = pixel_check_boundary && true;
  //       // } else {
  //       //   pixel_check_boundary = false;
  //       // }
  //       if Rgba(rgba) == self.boundary_color {
  //         // yAxis.push(2);
  //         println!("pixel:{:?}", pixel);
  //         pixel_check_boundary = pixel_check_boundary && true;
  //       } else {
  //         pixel_check_boundary = false;
  //       }
  //     }

  //     // 行尾检测
  //     if is_end_of_line {
  //       // println!(
  //       //   "行尾检测{curr_y}=>last_line_is_boundary:{}",
  //       //   last_line_is_boundary
  //       // );
  //       // println!(
  //       //   "行尾检测{curr_y}=>pixel_check_boundary:{}",
  //       //   pixel_check_boundary
  //       // );
  //       if last_line_is_boundary {
  //         if !pixel_check_boundary {
  //           y_axises.push(curr_y - 1);
  //         }
  //       } else {
  //         if pixel_check_boundary {
  //           y_axises.push(curr_y);
  //         }
  //       }
  //       last_line_is_boundary = pixel_check_boundary;
  //     }
  //   }

  //   println!("split yAxises:{:?}", y_axises);

  //   //前提 因为分割线一定不止1px的高度,因此每条线占用2个y_axis
  //   assert_eq!(0, y_axises.len() % 2);
  //   let y_axises = match &y_axises[..] {
  //     [] => {
  //       println!("没有找到任何边界,不做处理!");
  //       return Ok(vec![]);
  //     }
  //     [_] => {
  //       println!("只找到到一条边界(1px),不做处理!");
  //       return Ok(vec![]);
  //     }
  //     [_, _] => {
  //       println!("只找到到一条边界(>1px),不做处理!");
  //       return Ok(vec![]);
  //     }
  //     // 去除第一个和最后一个数据后,每两个元素组成top和bottom的边界
  //     [_, remains @ .., _] => remains,
  //   };
  //   // // 去除第一个和最后一个数据后,每两个元素组成top和bottom的边界
  //   // let y_axises = &y_axises[1..y_axises.len() - 1];
  //   assert_eq!(0, y_axises.len() % 2);

  //   let (top, bottom): (Vec<(usize, &u32)>, Vec<(usize, &u32)>) = y_axises
  //     .into_iter()
  //     .enumerate()
  //     .partition(|(idx, _)| idx % 2 == 0);

  //   let (_, top): (Vec<_>, Vec<u32>) = top.into_iter().unzip();
  //   let (_, bottom): (Vec<_>, Vec<u32>) = bottom.into_iter().unzip();

  //   println!("top:{:?}", top);
  //   println!("bottom:{:?}", bottom);
  //   // let rects = top.iter().zip(bottom.iter()).map(|p| Rect {
  //   //   x: self.left_crop,
  //   //   y: *p.0,
  //   //   w: w - self.left_crop - self.right_crop,
  //   //   h: p.1 - p.0,
  //   // });
  //   let rects = top.iter().zip(bottom.iter()).filter_map(|p| {
  //     let rect_h = p.1 - p.0;
  //     if rect_h <= 10 {
  //       return None;
  //     }
  //     Some(Rect {
  //       x: self.left_crop,
  //       y: *p.0,
  //       w: w - self.left_crop - self.right_crop,
  //       h: rect_h,
  //     })
  //   });
  //   println!("rects:{:?}", rects);

  //   // let img = image::open(self.path.as_ref()).unwrap();
  //   let path = self.path.as_ref();
  //   let ext = path.extension().unwrap().to_str().unwrap();
  //   let filename = path.with_extension("").to_str().unwrap().to_string();

  //   for rect in rects {
  //     println!("rect:{:?}", rect);
  //     // let img1 = img.crop_imm(rect.x, rect.y, rect.w, rect.h).sav;
  //     // img.crop_imm(rect.x, rect.y, rect.w, rect.h).save(self.path.as_ref()).map_err(|err| {
  //     //   Err::<(), io::Error>(io::Error::new(io::ErrorKind::Other, "save img fail"))
  //     // });

  //     let file = format!(
  //       "{}_{}_{}_{}_{}.{}",
  //       filename, rect.x, rect.y, rect.w, rect.h, ext
  //     );
  //     if let Err(err) = img.crop_imm(rect.x, rect.y, rect.w, rect.h).save(file) {
  //       return Err(io::Error::new(io::ErrorKind::Other, err));
  //     }
  //   }
  //   Ok(vec![])
  // }
}
